; ------------------------------------------
; Title: OpenGL test
; 
; Author: Franck Charlet.
;
; Notes: Just a little example on how to use OpenGL.
;    Needs OpenGl32.dll and Glu32.dll (should be no problem).
;    Object have 2112 faces / 3 (weird) moving light sources
;    and it's f***ing slow on my cyrix 133.
;
; ------------------------------------------

; --- modified for WinInc includes by japheth
; --- best viewed with TABSIZE 4

; --------------- Assembler directives
		.386
		.387
		.model	flat,stdcall
		option	casemap:none  

; --------------- External includes
WIN32_LEAN_AND_MEAN equ 1
		.nolist
		.nocref
		include windows.inc
		include GL\GL.inc
		include GL\GLU.inc
		.cref
		.list

; --------------- Macros Section
szText MACRO Name,Text:VARARG
	LOCAL lbl
	jmp lbl
Name db Text,0
lbl:
	ENDM

m2m MACRO M1, M2
	push M2
	pop M1
	ENDM

return MACRO arg
	mov eax,arg
	ret
	ENDM

; --------------- These constants are not defined in windows.inc
PFD_MAIN_PLANE		equ	0
PFD_TYPE_COLORINDEX	equ	1
PFD_TYPE_RGBA		equ	0
PFD_DOUBLEBUFFER	equ	1
PFD_DRAW_TO_WINDOW	equ	4
PFD_SUPPORT_OPENGL	equ	020h

; --------------- Data Section
		.data

szDisplayName		db	"TestOpenGL - Written by Franck 'hitchhikr' Charlet.",0

		align 4

PixFrm		PIXELFORMATDESCRIPTOR <>

CommandLine		dd	0
hWnd			dd	0
MainHDC			dd	0
OpenDC			dd	0
hInstance		dd	0

; Some values
Value0Flt		dd	0.0
Value1Flt		dd	1.0
Value1Dbl		dq	1.0
Value45Dbl		dq	45.0
Value3Dbl		dq	3.0
Value7Dbl		dq	7.0

; Light position
LightSourcePosition	dd	-2.0,-2.0,-4.0,0.0
LightSource2Position	dd	2.0,2.0,4.0,0.0
LightSource3Position	dd	-2.0,2.0,4.0,0.0
LightAmbient		dd	0.2,0.0,0.0,1.0
Light2Ambient		dd	0.0,0.2,0.0,1.0
Light3Ambient		dd	0.0,0.0,0.2,1.0
LightDiffuse		dd	1.0,1.0,1.0,1.0
LightSpecular		dd	1.0,1.0,1.0,1.0
SpotCut				dd	-1.0
SpotExp				dd	0.0
SpotDir				dd	-1.0,-1.0,-1.0
LightConstAtt		dd	1.0
LightLinAtt			dd	1.0
LightQuadAtt		dd	1.0

; --- Sphere 1
; Angles
Sphere1AnglesFlt	dd	0.0,0.0,0.0
; Rotations speed
Sphere1AnglesSpeedFlt	dd	-1.0,-1.2,-1.4
; Objects datas
Sphere1Color		dd	0.6,0.4,0.2,0.0
Sphere1Radius		dq	1.0
sphere1Parts		dd	24
Sphere1Position		dd	0.0,0.0,-5.0
GlSphere1			dd	0

; --- Sphere 2
; Angles
Sphere2AnglesFlt	dd	0.0,0.0,0.0
; Rotations speed
Sphere2AnglesSpeedFlt	dd	-1.0,0.8,-0.4
; Objects datas
Sphere2Color		dd	0.4,0.6,0.2,0.0
Sphere2Radius		dq	0.3
sphere2Parts		dd	16
Sphere2Position		dd	0.0,0.0,-1.5
GlSphere2			dd	0

; --- Sphere 3
; Angles
Sphere3AnglesFlt	dd	0.0,0.0,0.0
; Rotations speed
Sphere3AnglesSpeedFlt	dd	-1.0,-0.8,1.4
; Objects datas
Sphere3Color		dd	0.2,0.4,0.6,0.0
Sphere3Radius		dq	0.3
sphere3Parts		dd	16
Sphere3Position		dd	0.0,0.0,1.5
GlSphere3			dd	0

; --- Sphere 4
; Angles
Sphere4AnglesFlt	dd	0.0,0.0,0.0
; Rotations speed
Sphere4AnglesSpeedFlt	dd	-1.0,1.4,-0.8
; Objects datas
Sphere4Color		dd	0.4,0.2,0.6,0.0
Sphere4Radius		dq	0.3
sphere4Parts		dd	16
Sphere4Position		dd	0.0,1.5,0.0
GlSphere4			dd	0

; --- Sphere 5
; Angles
Sphere5AnglesFlt	dd	0.0,0.0,0.0
; Rotations speed
Sphere5AnglesSpeedFlt	dd	1.0,1.8,0.8
; Objects datas
Sphere5Color		dd	0.6,0.2,0.4,0.0
Sphere5Radius		dq	0.3
sphere5Parts		dd	16
Sphere5Position		dd	1.5,0.0,0.0
GlSphere5			dd	0

; --- Sphere 6
; Angles
Sphere6AnglesFlt	dd	0.0,0.0,0.0
; Rotations speed
Sphere6AnglesSpeedFlt	dd	1.0,-1.8,2.0
; Objects datas
Sphere6Color		dd	0.2,0.6,0.4,0.0
Sphere6Radius		dq	0.3
sphere6Parts		dd	16
Sphere6Position		dd	-1.5,0.0,0.0
GlSphere6			dd	0

; --- Sphere 7
; Angles
Sphere7AnglesFlt	dd	0.0,0.0,0.0
; Rotations speed
Sphere7AnglesSpeedFlt	dd	-2.1,-1.8,2.0
; Objects datas
Sphere7Color		dd	0.6,0.6,0.6,0.0
Sphere7Radius		dq	0.3
sphere7Parts		dd	16
Sphere7Position		dd	0.0,-1.5,0.0
GlSphere7			dd	0

; --------------- Procedures Declarations
		.code

MainInit		PROTO	:DWORD,:DWORD,:DWORD,:DWORD
MainLoop		PROTO	:DWORD,:DWORD,:DWORD,:DWORD
TopXY			PROTO	:DWORD,:DWORD
DrawScene		PROTO
GlInit			PROTO	:DWORD,:DWORD
ResizeObject	PROTO	:DWORD,:DWORD
CreateSphere	PROTO	:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
SetLightSource	PROTO	:DWORD,:DWORD,:DWORD
RotateObject	PROTO	:DWORD,:DWORD,:DWORD,:DWORD
DeleteSpheres	PROTO

; --------------- Procedures Section
CenterForm	PROC	wDim:DWORD, sDim:DWORD
		shr	sDim,1
		shr	wDim,1
		mov	eax,wDim
		sub	sDim,eax
		return	sDim
CenterForm	ENDP

DoEvents	PROC
		LOCAL	msg:MSG
StartLoop:		; Check for waiting messages
		invoke	PeekMessage,ADDR msg,0,0,0,PM_NOREMOVE
		or	eax,eax
		jz	NoMsg
		invoke	GetMessage,ADDR msg,NULL,0,0
		or	eax,eax
		jz	ExitLoop
		invoke	TranslateMessage,ADDR msg
		invoke	DispatchMessage,ADDR msg
		jmp	StartLoop
NoMsg:			; No pending messages: draw the scene
		invoke	DrawScene
		jmp	StartLoop
ExitLoop:
		mov	eax,msg.wParam
		ret
DoEvents	ENDP

; --------------- Program start

		public start
start:
		invoke	GetModuleHandle,NULL
		mov	hInstance, eax
		invoke	GetCommandLine
		mov	CommandLine,eax
		invoke	MainInit,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
		invoke	ExitProcess,eax

; --------------- Program main inits
MainInit 		PROC	hInst:DWORD,hPrevInst:DWORD,CmdLine:DWORD,CmdShow:DWORD
		LOCAL	wc:WNDCLASSEX
		LOCAL	Wwd:DWORD
		LOCAL	Wht:DWORD
		LOCAL	Wtx:DWORD
		LOCAL	Wty:DWORD
	    szText	szClassName,"Win32SDI_Class"
		mov	wc.cbSize,sizeof WNDCLASSEX
		mov	wc.style,0
		mov	wc.lpfnWndProc,offset MainLoop
		mov	wc.cbClsExtra,NULL
		mov	wc.cbWndExtra,NULL
		m2m	wc.hInstance,hInst
		mov	wc.hbrBackground,COLOR_WINDOWTEXT+1
		mov	wc.lpszMenuName,NULL
		mov	wc.lpszClassName,offset szClassName
		invoke	LoadCursor,NULL,IDC_ARROW
		mov	wc.hCursor,eax
		mov	wc.hIcon,0
		mov	wc.hIconSm,0
		invoke	RegisterClassEx, ADDR wc
		mov	Wwd,400
		mov	Wht,420
		invoke	GetSystemMetrics,SM_CXSCREEN
		invoke	CenterForm,Wwd,eax
		mov	Wtx,eax
		invoke	GetSystemMetrics,SM_CYSCREEN
		invoke	CenterForm,Wht,eax
		mov	Wty,eax
		invoke	CreateWindowEx,0,ADDR szClassName,\
				ADDR szDisplayName,\
				WS_OVERLAPPEDWINDOW or WS_CLIPSIBLINGS or WS_CLIPCHILDREN,\
				Wtx,Wty,Wwd,Wht,\
				NULL,NULL,\
				hInst,NULL
		mov	hWnd,eax
		invoke	ShowWindow,hWnd,SW_SHOWNORMAL
		call	DoEvents
		ret
MainInit 	ENDP

; --------------- Program main loop
MainLoop	PROC	hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
		LOCAL	WINRect:RECT
		LOCAL	PixFormat:DWORD
		.if uMsg == WM_KEYDOWN
			.if wParam == VK_ESCAPE
				invoke	SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,NULL
			.endif
			return	0
		.elseif	uMsg == WM_CREATE
			invoke	GetDC,hWin
			mov	MainHDC,eax
			mov	ax,SIZEOF PixFrm
			mov	PixFrm.nSize,ax
			mov	PixFrm.nVersion,1
			mov	PixFrm.dwFlags,PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER
			mov	PixFrm.dwLayerMask,PFD_MAIN_PLANE
			mov	PixFrm.iPixelType,PFD_TYPE_RGBA
			mov	PixFrm.cColorBits,8
			mov	PixFrm.cDepthBits,16
			mov	PixFrm.cAccumBits,0
			mov	PixFrm.cStencilBits,0
			invoke	ChoosePixelFormat,MainHDC,ADDR PixFrm
			mov	PixFormat,eax
			invoke	SetPixelFormat,MainHDC,PixFormat,ADDR PixFrm
			or	eax,eax
			jz	NoPixelFmt
			invoke	wglCreateContext,MainHDC
			mov	OpenDC,eax
			invoke	wglMakeCurrent,MainHDC,OpenDC
			invoke	GetClientRect,hWin,ADDR WINRect
			invoke	GlInit,WINRect.right,WINRect.bottom
NoPixelFmt:		
			return	0
		.elseif	uMsg == WM_SIZE
			invoke	GetClientRect,hWin,ADDR WINRect
			invoke	ResizeObject,WINRect.right,WINRect.bottom
			return	0
				
		.elseif	uMsg == WM_CLOSE
if 0        
			szText TheText,"Are you sure ?"
			invoke	MessageBox,hWin,ADDR TheText,ADDR szDisplayName,MB_YESNO+MB_ICONQUESTION
			.if eax == IDNO
				return	0
			.endif
endif            
			mov	eax,OpenDC
			or	eax,eax
			jz	NoGlDC
			; Delete our objects
			invoke	DeleteSpheres
			invoke	wglDeleteContext,OpenDC
NoGlDC:
			invoke	ReleaseDC,hWin,MainHDC
			invoke	DestroyWindow,hWin
			return	0
		.elseif uMsg == WM_DESTROY
			invoke	PostQuitMessage,NULL
			return	0 
		.endif
		invoke	DefWindowProc,hWin,uMsg,wParam,lParam
		ret
MainLoop	ENDP

; ------------------------------
; OpenGl related stuff
; ------------------------------

; --------------- Init the scene
GlInit	PROC	ParentW:DWORD,ParentH:DWORD
		invoke	SetLightSource,GL_LIGHT0,ADDR LightSourcePosition,ADDR LightAmbient
		invoke	SetLightSource,GL_LIGHT1,ADDR LightSource2Position,ADDR Light2Ambient
		invoke	SetLightSource,GL_LIGHT2,ADDR LightSource3Position,ADDR Light3Ambient
		invoke	CreateSphere,1,GLU_FILL,GLU_SMOOTH,ADDR Sphere1Color,ADDR Sphere1Radius,sphere1Parts
		mov	GlSphere1,eax
		invoke	CreateSphere,2,GLU_FILL,GLU_SMOOTH,ADDR Sphere2Color,ADDR Sphere2Radius,sphere2Parts
		mov	GlSphere2,eax
		invoke	CreateSphere,3,GLU_FILL,GLU_SMOOTH,ADDR Sphere3Color,ADDR Sphere3Radius,sphere3Parts
		mov	GlSphere3,eax
		invoke	CreateSphere,4,GLU_FILL,GLU_SMOOTH,ADDR Sphere4Color,ADDR Sphere4Radius,sphere4Parts
		mov	GlSphere4,eax
		invoke	CreateSphere,5,GLU_FILL,GLU_SMOOTH,ADDR Sphere5Color,ADDR Sphere5Radius,sphere5Parts
		mov	GlSphere5,eax
		invoke	CreateSphere,6,GLU_FILL,GLU_SMOOTH,ADDR Sphere6Color,ADDR Sphere6Radius,sphere6Parts
		mov	GlSphere6,eax
		invoke	CreateSphere,7,GLU_FILL,GLU_SMOOTH,ADDR Sphere7Color,ADDR Sphere7Radius,sphere7Parts
		mov	GlSphere7,eax
		; Set global flags
		invoke	glEnable,GL_DEPTH_TEST
		invoke	glEnable,GL_LIGHTING
		invoke	glEnable,GL_CULL_FACE		; Don't render back faces
		invoke	glShadeModel,GL_SMOOTH
		invoke	glEnable,GL_NORMALIZE
		ret
GlInit	ENDP

; --------------- Display the scene
DrawScene	PROC
		invoke	glClear,GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT
		invoke	glPushMatrix
		invoke	RotateObject,1,ADDR Sphere1Position,ADDR Sphere1AnglesSpeedFlt,ADDR Sphere1AnglesFlt
		invoke	glPushMatrix
		invoke	RotateObject,2,ADDR Sphere2Position,ADDR Sphere2AnglesSpeedFlt,ADDR Sphere2AnglesFlt
		invoke	glLightfv,GL_LIGHT0,GL_POSITION,ADDR LightSourcePosition
		invoke	glPopMatrix
		invoke	glPushMatrix
		invoke	RotateObject,3,ADDR Sphere3Position,ADDR Sphere3AnglesSpeedFlt,ADDR Sphere3AnglesFlt
		invoke	glLightfv,GL_LIGHT1,GL_POSITION,ADDR LightSource2Position
		invoke	glPopMatrix
		invoke	glPushMatrix
		invoke	RotateObject,4,ADDR Sphere4Position,ADDR Sphere4AnglesSpeedFlt,ADDR Sphere4AnglesFlt
		invoke	glLightfv,GL_LIGHT2,GL_POSITION,ADDR LightSource3Position
		invoke	glPopMatrix
		invoke	glPushMatrix
		invoke	RotateObject,5,ADDR Sphere5Position,ADDR Sphere5AnglesSpeedFlt,ADDR Sphere5AnglesFlt
		invoke	glPopMatrix
		invoke	glPushMatrix
		invoke	RotateObject,6,ADDR Sphere6Position,ADDR Sphere6AnglesSpeedFlt,ADDR Sphere6AnglesFlt
		invoke	glPopMatrix
		invoke	glPushMatrix
		invoke	RotateObject,7,ADDR Sphere7Position,ADDR Sphere7AnglesSpeedFlt,ADDR Sphere7AnglesFlt
		invoke	glPopMatrix
		invoke	glPopMatrix
		invoke	SwapBuffers,MainHDC
		ret
DrawScene	ENDP

; --------------- Resize the scene
ResizeObject	PROC	ParentW:DWORD,ParentH:DWORD
		invoke	glViewport,0,0,ParentW,ParentH
		invoke	glMatrixMode,GL_PROJECTION
		invoke	glLoadIdentity
		invoke	gluPerspective, Value45Dbl, Value1Dbl, Value3Dbl, Value7Dbl 
		invoke	glMatrixMode,GL_MODELVIEW
		invoke	glLoadIdentity
		ret
ResizeObject	ENDP

; --------------- Free the memory allocated for the spheres
DeleteSpheres	PROC
		invoke	gluDeleteQuadric,GlSphere1
		invoke	gluDeleteQuadric,GlSphere2
		invoke	gluDeleteQuadric,GlSphere3
		invoke	gluDeleteQuadric,GlSphere4
		invoke	gluDeleteQuadric,GlSphere5
		invoke	gluDeleteQuadric,GlSphere6
		invoke	gluDeleteQuadric,GlSphere7
		ret
DeleteSpheres	ENDP

; --------------- Create a sphere with glu object
CreateSphere	PROC	ListNumber:DWORD,FillType:DWORD,NormalsType:DWORD,Color:DWORD,Radius:DWORD,Parts:DWORD
		LOCAL	GlSphere:DWORD
		invoke	glNewList,ListNumber,GL_COMPILE
		; Create a template
		invoke	gluNewQuadric
		mov	GlSphere,eax
		; Set object draw style
		invoke	gluQuadricDrawStyle,GlSphere,FillType
		; Set normals style
		invoke	gluQuadricNormals,GlSphere,NormalsType
		; Set object color
		invoke	glMaterialfv,GL_FRONT,GL_AMBIENT_AND_DIFFUSE,Color
		mov	eax,Radius
		; Create a sphere primitive
		invoke	gluSphere, GlSphere,[eax], Parts, Parts
		invoke	glEndList
		mov	eax,GlSphere
		ret
CreateSphere	ENDP

; --------------- Set a light source
SetLightSource	PROC	LtNumber:DWORD,LtPosition:DWORD,LtAmbient:DWORD
		invoke	glLightfv,LtNumber,GL_POSITION,LtPosition
		invoke	glLightfv,LtNumber,GL_DIFFUSE,ADDR LightDiffuse
		invoke	glLightfv,LtNumber,GL_SPECULAR,ADDR LightSpecular
		invoke	glLightfv,LtNumber,GL_AMBIENT,LtAmbient
		invoke	glLightfv,LtNumber,GL_CONSTANT_ATTENUATION,ADDR LightConstAtt
		invoke	glLightfv,LtNumber,GL_LINEAR_ATTENUATION,ADDR LightLinAtt
		invoke	glLightfv,LtNumber,GL_QUADRATIC_ATTENUATION,ADDR LightQuadAtt
		invoke	glLightfv,LtNumber,GL_SPOT_CUTOFF,ADDR SpotCut
		invoke	glLightfv,LtNumber,GL_SPOT_EXPONENT,ADDR SpotExp
		invoke	glLightfv,LtNumber,GL_SPOT_DIRECTION,ADDR SpotDir
		invoke	glEnable,LtNumber
		ret	
SetLightSource	ENDP

; --------------- Position and rotate an object
RotateObject	PROC	ListNumber:DWORD,XYZPosition:DWORD,XYZRotations:DWORD,XYZAngles:DWORD
		LOCAL	LocXSpd:DWORD
		LOCAL	LocYSpd:DWORD
		LOCAL	LocZSpd:DWORD
		LOCAL	LocXAngle:DWORD
		LOCAL	LocYAngle:DWORD
		LOCAL	LocZAngle:DWORD
		mov	eax,XYZPosition
		mov	ecx,[eax]
		mov	ebx,[eax+4]
		mov	eax,[eax+8]
		invoke	glTranslatef,ecx,ebx,eax
		mov	eax,XYZAngles			; Rotate X
		mov	ebx,XYZRotations
		fld		DWORD PTR [eax]
		fadd	DWORD PTR [ebx]
		fstp	DWORD PTR [eax]
		invoke	glRotatef,[eax],Value0Flt,Value1Flt,Value0Flt
		mov	eax,XYZAngles			; Rotate Y
		mov	ebx,XYZRotations
		fld		DWORD PTR [eax+4]
		fadd	DWORD PTR [ebx+4]
		fstp	DWORD PTR [eax+4]
		invoke	glRotatef,[eax+4],Value1Flt,Value0Flt,Value0Flt
		mov	eax,XYZAngles			; Rotate Z
		mov	ebx,XYZRotations
		fld		DWORD PTR [eax+8]
		fadd	DWORD PTR [ebx+8]
		fstp	DWORD PTR [eax+8]
		invoke	glRotatef,DWORD PTR [eax+8],Value0Flt,Value0Flt,Value1Flt
		invoke	glCallList,ListNumber
		ret
RotateObject	ENDP

; --------------- Program end
end start
